package net.gpai.tool

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTransformGestures
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
import androidx.compose.foundation.lazy.staggeredgrid.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.toComposeImageBitmap
import androidx.compose.ui.input.pointer.*
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Window
import gtool.composeapp.generated.resources.Res
import gtool.composeapp.generated.resources.gpai_icon
import io.github.vinceglb.filekit.FileKit
import io.github.vinceglb.filekit.PlatformFile
import io.github.vinceglb.filekit.dialogs.FileKitMode
import io.github.vinceglb.filekit.dialogs.FileKitType
import io.github.vinceglb.filekit.dialogs.openFilePicker
import io.github.vinceglb.filekit.name
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import net.gpai.logger.logger
import org.jetbrains.compose.resources.painterResource
import java.awt.Desktop
import java.awt.Graphics2D
import java.awt.Image.SCALE_SMOOTH
import java.awt.RenderingHints
import java.awt.image.BufferedImage
import java.io.File
import javax.imageio.ImageIO

private val log = logger("Index")

@Composable
@Preview
fun Index() {
    var previewFile by remember { mutableStateOf<PlatformFile?>(null) }
    val imagesList = remember { mutableStateListOf<PlatformFile>() }
    val scope = rememberCoroutineScope()

    /* 1. 当前要预览的图片 */
    var prefix by remember { mutableStateOf("") }
    var outputDir by remember { mutableStateOf<String?>(null) }
    var outputQuality by remember { mutableStateOf(90f) }
    var processing by remember { mutableStateOf(false) }
    var showDialog by remember { mutableStateOf(false) }
    var dialogMsg by remember { mutableStateOf("") }

    Column(Modifier.fillMaxSize()) {

        Column(
            modifier = Modifier.fillMaxWidth().padding(horizontal = 10.dp),
            verticalArrangement = Arrangement.spacedBy(10.dp),
        ) {
//            Tips(modifier = Modifier.padding(top = 15.dp))
            Column(horizontalAlignment = Alignment.Start, modifier = Modifier.fillMaxWidth().padding(top = 15.dp)) {
                Row(
                    verticalAlignment = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.spacedBy(6.dp)
                ) {
                    Button(
                        enabled = !processing,
                        modifier = Modifier.width(150.dp),
                        onClick = {
                            scope.launch {
                                try {
                                    // 只允许选择图片
                                    val selectedFiles =
                                        FileKit.openFilePicker(mode = FileKitMode.Multiple(), type = FileKitType.Image)
                                    // 选择后加入集合
                                    selectedFiles?.let { newFiles ->
                                        scope.launch {
                                            withContext(Dispatchers.Default) { // 使用 Default 避免阻塞 UI
                                                val filtered = newFiles.filter { newFile ->
                                                    val newPath = newFile.file.absolutePath
                                                    imagesList.none { it.file.absolutePath == newPath }
                                                }
                                                withContext(Dispatchers.Main) { // 回到主线程更新 UI
                                                    imagesList.addAll(filtered)
                                                }
                                            }
                                        }
                                    }
                                } catch (e: Exception) {
                                    log.error("选择图片发生错误:", e)
                                }
                            }
                        }) {
                        Text("选择文件")
                    }

                    if (imagesList.isNotEmpty()) {
                        Spacer(Modifier.width(10.dp))
                        Button(
                            enabled = !processing,
                            modifier = Modifier.width(150.dp),
                            onClick = {
                                imagesList.clear()
                            }) {
                            Text("清空文件")
                        }

                        Spacer(Modifier.width(10.dp))
                        LoadingButton(
                            onClick = {
                                processing = true
                                outputDir = null
                                scope.launch {
                                    // 模拟用时
//                                    delay(3_000)            // 挂起 3 秒
//                                    processing = false         // 自动关闭加载
//                                    showDialog = true

                                    withContext(Dispatchers.IO) {
                                        val toList = imagesList.let { images -> images.map { image -> image.file } }
                                        // 压缩图片
                                        try {
                                            val compressResult =
                                                compressImages(toList, outputQuality = outputQuality, prefix)

                                            outputDir = compressResult.baseDir
                                            if (compressResult.errorItem.isEmpty()) {
                                                showDialog = true
                                                dialogMsg = "处理完成"
                                            } else {
                                                showDialog = true
                                                dialogMsg =
                                                    "处理完成,但有部分数据处理失败:${compressResult.getErrorInfo()}"
                                            }
                                        } catch (e: Exception) {
                                            showDialog = true
                                            dialogMsg = "发生错误:${e.message}!"
                                        }
                                        processing = false         // 自动关闭加载
                                    }
                                }
                            },
                            enabled = !processing,
                            text = if (!processing) {
                                "立即处理"
                            } else {
                                "正在处理"
                            },
                            loading = processing,
                            modifier = Modifier.align(Alignment.CenterVertically).width(150.dp)
                        )
                    }
                    outputDir?.let {
                        Text(
                            "打开文件夹", modifier = Modifier.align(Alignment.CenterVertically)
                                .padding(10.dp)
                        )
                        Text(
                            text = "$outputDir",
                            fontSize = 15.sp,
                            maxLines = 1,
                            textDecoration = TextDecoration.Underline,
                            overflow = TextOverflow.Ellipsis,
                            modifier = Modifier.align(Alignment.CenterVertically)
                                .pointerHoverIcon(PointerIcon.Hand)
                                .clickable {
                                    scope.launch {
                                        try {
                                            Desktop.getDesktop().open(File(outputDir!!))
                                        } catch (e: Exception) {
                                            showDialog = true
                                            dialogMsg = "打开文件夹失败:${e.message}"
                                        }
                                    }
                                },
                        )
                    }
                }
                Column() {
                    TextField(
                        value = prefix,
                        modifier = Modifier.padding(vertical = 15.dp).fillMaxWidth(),
                        onValueChange = { prefix = it },
                        placeholder = {
                            Text(
                                "如果需要批量重命名,例如将文件重命名为A_1,A_2...A100,那么这里写A_，留空则不进行重命名",
                                color = Color.Gray
                            )
                        },
                        singleLine = true,
                    )
                    Text("图片质量（可选范围50-100，质量越高图片清晰度越高）", fontSize = 15.sp, color = Color.Gray)
                    Row(verticalAlignment = Alignment.CenterVertically) {
                        Slider(
                            enabled = !processing,
                            value = outputQuality,
                            valueRange = 50f..100f,
                            onValueChange = {
                                outputQuality = it
                            },
                            modifier = Modifier.weight(1f)
                        )
                        Spacer(Modifier.width(12.dp))
                        Text("%.0f".format(outputQuality))   // 实时显示 0~100
                    }
                }
            }
        }
        HorizontalDivider(
            modifier = Modifier.padding(top = 15.dp, bottom = 5.dp),
            thickness = 1.dp,
            color = Color.LightGray
        )
        // 绘制一个分割线
        LazyVerticalStaggeredGrid(
            modifier = Modifier.fillMaxWidth().padding(10.dp),
            columns = StaggeredGridCells.Adaptive(120.dp),
            verticalItemSpacing = 10.dp,
            horizontalArrangement = Arrangement.spacedBy(10.dp),
            content = {
                items(imagesList) { platformFile ->
                    ImgBox(
                        platformFile,
                        onPreviewFileChange = { newFile ->
                            scope.launch {
                                withContext(Dispatchers.Default) {
                                    previewFile = newFile
                                }
                            }
                        },
                        onDeleteFileChange = { newFile ->
                            scope.launch {
                                withContext(Dispatchers.Default) {
                                    imagesList.remove(newFile)
                                }
                            }
                        },
                        processing = processing,
                    )
                }
            }
        )
    }


    //每当 previewFile 的值 发生变化，Compose 会 自动重组 这段 UI，于是 previewFile?.let { ... } 会重新执行一次判断决定是否显示这个window
    previewFile?.let { pf ->
        Window(
            onCloseRequest = { previewFile = null },
            title = pf.name,
            icon = painterResource(Res.drawable.gpai_icon),
            resizable = true
        ) {
            Surface(Modifier.fillMaxSize()) {
                Box(Modifier.fillMaxSize()) {
                    /* 4. 原图加载，可再包一个 Scrollable + Zoomable，这里仅演示 */
                    val bitmap = remember(pf.file) {
                        pf.file.inputStream().use { ImageIO.read(it) }
                            ?.toComposeImageBitmap()
                    }
                    bitmap?.let {

                        // 包一个可缩放组件
                        Zoomable(
                            modifier = Modifier.fillMaxSize(),
                            minScale = 0.6f,
                            maxScale = 6f,
                        ) {
                            Image(
                                bitmap = it,
                                contentDescription = pf.file.absolutePath,
                                modifier = Modifier.fillMaxSize(),
                                contentScale = ContentScale.Fit
                            )
                        }

                    }

                    /* 5. 关闭按钮 */
//                    IconButton(
//                        onClick = { previewFile = null },
//                        modifier = Modifier.align(Alignment.TopEnd).padding(8.dp)
//                    ) {
//                        Icon(
//                            imageVector = Icons.Default.Close,
//                            contentDescription = "关闭",
//                            tint = Color.White,
//                            modifier = Modifier
//                                .size(24.dp)
//                                .background(Color.Black.copy(alpha = 0.5f), CircleShape)
//                        )
//                    }
                }
            }
        }
    }

    if (showDialog) {
        AlertDialog(
            onDismissRequest = {
                showDialog = false; dialogMsg = ""
            },   // 点空白处或按返回键
            title = { Text("提示") },
            text = { Text(dialogMsg) },
            confirmButton = {
                TextButton(onClick = { showDialog = false; dialogMsg = "" }) {
                    Text("确定")
                }
            },
//            dismissButton = {
//                TextButton(onClick = { showDialog = false }) {
//                    Text("取消")
//                }
//            }
        )
    }

}

/* 等比缩放工具函数 */
private fun scaleBufferedImage(src: BufferedImage, max: Int): BufferedImage {
    val (w, h) = if (src.width > src.height) {
        max to (src.height * max.toDouble() / src.width).toInt()
    } else {
        (src.width * max.toDouble() / src.height).toInt() to max
    }
    val scaled = src.getScaledInstance(w, h, SCALE_SMOOTH)
    val buf = BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB)
    val g2d: Graphics2D = buf.createGraphics()
    g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
    g2d.drawImage(scaled, 0, 0, null)
    g2d.dispose()
    return buf
}


@Composable
private fun Thumbnail(file: File, contentDescription: String = "", onClick: () -> Unit) {
    val state by produceState<ThumbUiState>(ThumbUiState.Loading, file.absolutePath) {
        withContext(Dispatchers.IO) {
            value = try {
                when {
                    !file.exists() -> ThumbUiState.Error("文件不存在")
                    !file.canRead() -> ThumbUiState.Error("无读取权限")
                    else -> {
                        val origin = ImageIO.read(file)
                        if (origin == null) {
                            ThumbUiState.Error("不是有效图片")
                        } else {
                            val small = scaleBufferedImage(origin, 100)
                            ThumbUiState.Ok(small.toComposeImageBitmap())
                        }
                    }
                }
            } catch (e: Exception) {
                log.error("图像读取失败:", e)
                ThumbUiState.Error(e.message ?: "读取失败")
            }
        }
    }

    Box(
        modifier = Modifier
            .width(100.dp)
            .height(100.dp)
            .padding(5.dp)
            .clickable { onClick() }
            .background(Color.LightGray.copy(alpha = 0.3f), RoundedCornerShape(4.dp)),
        contentAlignment = Alignment.Center
    ) {
        when (state) {
            ThumbUiState.Loading ->
                CircularProgressIndicator(modifier = Modifier.size(24.dp))

            is ThumbUiState.Error -> {
                Column(horizontalAlignment = Alignment.CenterHorizontally) {
                    Text(
                        text = "❌",
                        fontSize = 18.sp,
                        color = Color.Red
                    )
                    Text(
                        text = (state as ThumbUiState.Error).msg,
                        fontSize = 10.sp,
                        color = Color.Red,
                        textAlign = TextAlign.Center,
                        modifier = Modifier.padding(horizontal = 4.dp)
                    )
                }
            }

            is ThumbUiState.Ok -> {
                Image(
                    bitmap = (state as ThumbUiState.Ok).bitmap,
                    contentDescription = contentDescription,
                    modifier = Modifier.fillMaxSize()
                )
            }
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
@Composable
private fun ImgBox(
    platformFile: PlatformFile,
    onPreviewFileChange: (PlatformFile?) -> Unit = {},
    onDeleteFileChange: (PlatformFile?) -> Unit = {},
    processing: Boolean = false,
) {
    // 鼠标悬浮显示删除按钮
    var hovered by remember { mutableStateOf(false) }
    // 文件名全名显示控制
    val tooltipState = rememberTooltipState()
    Column(
        modifier = Modifier.fillMaxWidth().border(width = 1.dp, color = Color.LightGray)
            .padding(horizontal = 10.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        // 显示图片，后面跟上文件名称
        val file = platformFile.file
        val contentDescription = file.absolutePath
        Thumbnail(file, contentDescription, onClick = { onPreviewFileChange(platformFile) })
        Box(
            modifier = Modifier.fillMaxWidth()
                .onPointerEvent(PointerEventType.Enter) {
                    hovered = true
                }.onPointerEvent(PointerEventType.Exit) {
                    hovered = false
                }
        ) {
            TooltipBox(
                positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
                tooltip = {
                    Surface(
                        shape = RoundedCornerShape(8.dp),
                        tonalElevation = 10.dp,
                        modifier = Modifier
                            .align(Alignment.CenterStart),
                    ) {
                        Text(
                            text = platformFile.name,
                            textAlign = TextAlign.Center,
                            modifier = Modifier.padding(horizontal = 15.dp, vertical = 10.dp)
                                .align(Alignment.CenterStart),
                            fontWeight = FontWeight.Bold,
                        )
                    }
                },
                state = tooltipState,
            ) {
                Row(
                    modifier = Modifier
                        .padding(3.dp)
                        .align(Alignment.Center)
                        .onPointerEvent(PointerEventType.Enter) { hovered = true }
                        .onPointerEvent(PointerEventType.Exit) { hovered = false },
                ) {
                    Text(
                        text = platformFile.name,
                        fontSize = 10.sp,
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis,
                        textAlign = TextAlign.Center,
                        modifier = Modifier
                            .weight(1f)
                            .align(Alignment.CenterVertically)
                            .padding(horizontal = 1.dp, vertical = 5.dp),
                    )
                    AnimatedVisibility(
                        visible = hovered && !processing,
                        modifier = Modifier.align(Alignment.CenterVertically)
                    ) {
                        Text(
                            text = "❎",
                            fontSize = 18.sp,
                            color = Color.Gray,
                            modifier = Modifier
                                .clickable {
                                    onDeleteFileChange(platformFile)
                                }
                                .padding(start = 1.dp)
                                .background(Color.White),
                        )
                    }
                }
            }
        }
    }


}



@Composable
fun Zoomable(
    modifier: Modifier = Modifier,
    minScale: Float = 0.5f,
    maxScale: Float = 5f,
    content: @Composable () -> Unit
) {
    var scale by remember { mutableStateOf(1f) }
    var offsetX by remember { mutableStateOf(0f) }
    var offsetY by remember { mutableStateOf(0f) }

    Box(
        modifier = modifier
            .clipToBounds()          // 把超出部分裁掉
            .pointerInput(Unit) {
                // 双指捏合
                detectTransformGestures { _, pan, zoom, _ ->
                    scale = (scale * zoom).coerceIn(minScale, maxScale)
                    // 放大后才能拖，否则不允许拖
                    if (scale > 1) {
                        offsetX += pan.x
                        offsetY += pan.y
                    }
                }
            }
            .pointerInput(Unit) {
                // 鼠标滚轮
                awaitPointerEventScope {
                    while (true) {
                        val event = awaitPointerEvent()
                        if (event.type == PointerEventType.Scroll) {
                            val delta = event.changes.first().scrollDelta
                            scale = (scale * (1 - delta.y * 0.1f)).coerceIn(minScale, maxScale)
                        }
                    }
                }
            }
            .graphicsLayer(
                scaleX = scale,
                scaleY = scale,
                translationX = offsetX,
                translationY = offsetY
            )
    ) {
        content()
    }
}

